#include "dspSimulator/targetMachine/dspInstruction.h"
#include "dspSimulator/targetMachine/dspInstInfo.h"

RegKind DspInstruction::getSrc1Reg32Kind(u32 src1, bool s) const {
    if (s == 0) {
        return static_cast<RegKind>(static_cast<u32>(RegKind::A0) + src1);
    } else {
        return static_cast<RegKind>(static_cast<u32>(RegKind::B0) + src1);
    }
}

RegKind DspInstruction::getSrc2Reg32Kind(u32 src2, bool s, bool x) const {
    if (s == 0 && x == 0 || s == 1 && x == 1) {
        return static_cast<RegKind>(static_cast<u32>(RegKind::A0) + src2);
    } else {
        return static_cast<RegKind>(static_cast<u32>(RegKind::B0) + src2);
    }
}

RegKind DspInstruction::getDstReg32Kind(u32 dst, bool s) const {
    if (s == 0) {
        return static_cast<RegKind>(static_cast<u32>(RegKind::A0) + dst);
    } else {
        return static_cast<RegKind>(static_cast<u32>(RegKind::B0) + dst);
    }
}


void DspInstruction::generateIRWithCondition(std::shared_ptr<IRGenerator> irGenerator, llvm::Function *function,
                                             RegCopy &regCopy) {
    if (creg_z == 0b0000 || creg_z == 0b0001 || creg_z == 0b1110 || creg_z == 0b1111) {
        generateIR(irGenerator,function,regCopy);
    } else {
        auto ifBB = llvm::BasicBlock::Create(*irGenerator->getLLVMContext(), "if", function);
        auto elseBB = llvm::BasicBlock::Create(*irGenerator->getLLVMContext(), "else", function);
        auto endBB = llvm::BasicBlock::Create(*irGenerator->getLLVMContext(), "end", function);
        auto irBuilder = irGenerator->getLLVMIRBuilder();
        llvm::Value *cond;
        if (creg_z == 0b0010) {
            cond = irBuilder->CreateICmpNE(regCopy["B0"], irBuilder->getInt32(0));
        } else if (creg_z == 0b0011) {
            cond = irBuilder->CreateICmpEQ(regCopy["B0"], irBuilder->getInt32(0));
        } else if (creg_z == 0b0100) {
            cond = irBuilder->CreateICmpNE(regCopy["B1"], irBuilder->getInt32(0));
        } else if (creg_z == 0b0101) {
            cond = irBuilder->CreateICmpEQ(regCopy["B1"], irBuilder->getInt32(0));
        } else if (creg_z == 0b0110) {
            cond = irBuilder->CreateICmpNE(regCopy["B2"], irBuilder->getInt32(0));
        } else if (creg_z == 0b0111) {
            cond = irBuilder->CreateICmpEQ(regCopy["B2"], irBuilder->getInt32(0));
        } else if (creg_z == 0b1000) {
            cond = irBuilder->CreateICmpNE(regCopy["A1"], irBuilder->getInt32(0));
        } else if (creg_z == 0b1001) {
            cond = irBuilder->CreateICmpEQ(regCopy["A1"], irBuilder->getInt32(0));
        } else if (creg_z == 0b1010) {
            cond = irBuilder->CreateICmpNE(regCopy["A2"], irBuilder->getInt32(0));
        } else if (creg_z == 0b1011) {
            cond = irBuilder->CreateICmpEQ(regCopy["A2"], irBuilder->getInt32(0));
        } else if (creg_z == 0b1100) {
            cond = irBuilder->CreateICmpNE(regCopy["A0"], irBuilder->getInt32(0));
        } else if (creg_z == 0b1101) {
            cond = irBuilder->CreateICmpEQ(regCopy["A0"], irBuilder->getInt32(0));
        } else {
            return;
        }
        irBuilder->CreateCondBr(cond, ifBB, elseBB);
        irBuilder->SetInsertPoint(ifBB);
        generateIR(irGenerator, function, regCopy);
        irBuilder->CreateBr(endBB);
        irBuilder->SetInsertPoint(elseBB);
        irBuilder->CreateBr(endBB);
        irBuilder->SetInsertPoint(endBB);
    }
}

bool DspInstruction::existStandardCondition(std::bitset<32> data) {
    std::bitset<4> creg_z = (data >> 28).to_ulong();
    switch (creg_z.to_ulong()) {
        case 0b0000:
        case 0b1110:
        case 0b1111:
        case 0b0010:
        case 0b0011:
        case 0b0100:
        case 0b0101:
        case 0b0110:
        case 0b0111:
        case 0b1000:
        case 0b1001:
        case 0b1010:
        case 0b1011:
        case 0b1100:
        case 0b1101:
            return true;
        default:
            return false;
    }
}